/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package dtomapper;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;

/**
 *
 * @author f4733401, Mlungisi Sincuba<mlungisi.sincuba@fnb.co.za>
 */
public class FileCreater {

    private static List<ClassProperties> generatedList(String packageName, List<String> entities) {
        List<ClassProperties> list = new ArrayList<>();
        try {
            for (String entity : entities) {
                ClassProperties cp = new ClassProperties();
                Class entityClass = Class.forName(packageName + entity);
                cp.setName(entity);
                cp.setSimpleName(entity);
                Field[] declaredFields = entityClass.getDeclaredFields();
                Map<String, String> fieldNameTypeMap = new HashMap<>();
                for (Field field : declaredFields) {
                    String propertyName = field.getName();
                    String simplePropertyName = cp.capitaliseAndSplit(propertyName);
                    fieldNameTypeMap.put(propertyName, simplePropertyName);
                }
                cp.setPropertyMap(fieldNameTypeMap);
                list.add(cp);
            }
        } catch (ClassNotFoundException ex) {
            System.err.println("ClassNotFoundException: " + ex);
        }
        return list;
    }

    private static List<ClassProperties> generatedListType(String packageName, List<String> entities) {
        List<ClassProperties> list = new ArrayList<>();
        try {
            for (String entity : entities) {
                ClassProperties cp = new ClassProperties();
                Class entityClass = Class.forName(packageName + entity);
                cp.setName(entity);
                cp.setSimpleName(entity);
                Field[] declaredFields = entityClass.getDeclaredFields();
                Map<String, String> fieldNameTypeMap = new HashMap<>();
                for (Field field : declaredFields) {
                    String propertyName = field.getName();
                    String type = field.getType().getName();
                    fieldNameTypeMap.put(propertyName, type);
                }
                cp.setPropertyMap(fieldNameTypeMap);
                list.add(cp);
            }
        } catch (ClassNotFoundException ex) {
            System.err.println("ClassNotFoundException: " + ex);
        }
        return list;
    }

    void generateMapper(String packageName, List<String> entities, String mapperPath) {
        System.out.println("packageName = " + packageName + "\nentities = " + entities);
        List<ClassProperties> generatedList = generatedListType(packageName, entities);
        BufferedReader br = null, br2 = null, br3 = null;
        BufferedWriter writer = null;
        try {
            String innerContent = "", content = "", outer = "", innerDto = "", innerE = "", line = null;
            for (ClassProperties classProperties : generatedList) {
                Map<String, String> propertyMap = classProperties.getPropertyMap();
                innerDto = "";
                innerE = "";
                for (Map.Entry<String, String> entry : propertyMap.entrySet()) {
                    String property = entry.getKey();
                    String type = entry.getValue();
                    br = new BufferedReader(new FileReader("basic-inner-inner-mapper.template"));
                    line = null;
                    while ((line = br.readLine()) != null) {
                        if (property.equals("serialVersionUID")) {
                            continue;
                        }
                        String setTo = StringUtils.capitalize(property);
                        
                        System.out.println("type: " + type);
                        if (line.contains("dto.set${property}(e.get${property}());")) {
                            if (type.startsWith("za.")) {
                                line = line.replace("e.get${property}()", "BasicEntityDTOMapper.map(e.get${property}())");
                            }
                            if (!(type.equals("long") || type.equals("int") || type.equals("short") || type.equals("byte") 
                                    || type.equals("char") || type.equals("boolean") || type.equals("double") || type.equals("float")) 
                                    && Collection.class.isAssignableFrom(Class.forName(type))) {
                                line = line.replace("e.get${property}()", "null");
                            } 
                            if (type.equals("boolean") || type.equals("java.lang.Boolean")) {
                                line = line.replace("e.get${property}()", "e.is${property}()");
                                line = line.replace("dto.get${property}()", "dto.is${property}()");
                            }
                            innerDto += line.replace("${property}", setTo) + "\n";
                        } else {
                            if (type.startsWith("za.")) {
                                line = line.replace("dto.get${property}()", "BasicEntityDTOMapper.map(dto.get${property}())");
                            }
                            
                            if (!(type.equals("long") || type.equals("int") || type.equals("short") || type.equals("byte") 
                                    || type.equals("char") || type.equals("boolean") || type.equals("double") || type.equals("float")) 
                                    && Collection.class.isAssignableFrom(Class.forName(type))) {
                                line = line.replace("dto.get${property}()", "null");
                            }
                            if (type.equals("boolean") || type.equals("java.lang.Boolean")) {
                                line = line.replace("e.get${property}()", "e.is${property}()");
                                line = line.replace("dto.get${property}()", "dto.is${property}()");
                            }
                            innerE += line.replace("${property}", setTo) + "\n";
                        }
                        //innerContent = innerContent + line.replace("${property}", StringUtils.capitalize(property)) + "\n";
                    }
                    br.close();
                }
                line = null;
                br2 = new BufferedReader(new FileReader("basic-inner-mapper.template"));
                while ((line = br2.readLine()) != null) {
                    content = content + line.replace("${inner-dto}", innerDto).replace("${class}", StringUtils.capitalize(classProperties.getName())).replace("${inner-e}", innerE) + "\n";
                }
                br2.close();
                
            }
            line = null;
            br3 = new BufferedReader(new FileReader("basic-mapper.template"));
            while ((line = br3.readLine()) != null) {
                outer = outer + line.replace("${inner}", content) + "\n";
            }
            br3.close();

            File file = new File(mapperPath + "/BasicEntityDTOMapper.java");
            writer = new BufferedWriter(new FileWriter(file));
            writer.write(outer);
            writer.flush();
            writer.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException ex) {
                    Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (br2 != null) {
                try {
                    br2.close();
                } catch (IOException ex) {
                    Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (br3 != null) {
                try {
                    br3.close();
                } catch (IOException ex) {
                    Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException ex) {
                    Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    void generateXmlProperty(String packageName, List<String> entities, String propertiesPath) {
        System.out.println("packageName = " + packageName + "\nentities = " + entities);
        List<ClassProperties> generatedList = generatedList(packageName, entities);
        BufferedReader br = null, br2 = null;
        BufferedWriter writer = null;
        try {
            for (ClassProperties classProperties : generatedList) {
                String innerContent = "", content = "", line = null;
                Map<String, String> propertyMap = classProperties.getPropertyMap();
                for (Map.Entry<String, String> entry : propertyMap.entrySet()) {
                    String property = entry.getKey();
                    String simplified = entry.getValue();
                    br = new BufferedReader(new FileReader("xml-properties-inner.template"));
                    while ((line = br.readLine()) != null) {
                        innerContent = innerContent + line.replace("${name}", property).replace("${simpleName}", simplified) + "\n";
                    }
                    br.close();
                }
                line = null;
                br2 = new BufferedReader(new FileReader("xml-properties.template"));
                while ((line = br2.readLine()) != null) {

                    content = content + line.replace("${inner}", innerContent).replace("${name}",
                            classProperties.getName()).replace("${simple}", classProperties.getSimpleName()) + "\n";
                }
                if (br != null) {
                    br.close();
                }
                br2.close();
                File file = new File(propertiesPath + "/" + classProperties.getName() + ".xml");
                writer = new BufferedWriter(new FileWriter(file));
                writer.write(content);
                writer.flush();
                writer.close();
            }
        } catch (FileNotFoundException ex) {
            Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException ex) {
                    Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (br2 != null) {
                try {
                    br2.close();
                } catch (IOException ex) {
                    Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException ex) {
                    Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    void generateMapper(List<String> entities, String mapperPath) {
        BufferedReader br = null, br2 = null;
        BufferedWriter writer = null;
        String innerContent = "", content = "", line = null;
        try {
            for (String entity : entities) {
                br = new BufferedReader(new FileReader("inner-mapper.template"));
                while ((line = br.readLine()) != null) {
                    innerContent = innerContent + line.replace("${class}", entity) + "\n";
                }
                br.close();
            }
            line = null;
            br2 = new BufferedReader(new FileReader("mapper.template"));
            while ((line = br2.readLine()) != null) {
                content = content + line.replace("${inner}", innerContent) + "\n";
            }

            writer = new BufferedWriter(new FileWriter(mapperPath + "/EntityDTOMapper.java"));
            writer.write(content);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException ex) {
                    Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (br2 != null) {
                try {
                    br2.close();
                } catch (IOException ex) {
                    Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (writer != null) {
                try {
                    writer.flush();
                    writer.close();
                } catch (IOException ex) {
                    Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    void generateMenubar(String entity, String menubarApth) {
        generate(entity, "menu-bar.template", menubarApth + "/" + entity + "Menubar.xhtml");
    }

    void generateDaoInterface(String entity, String daoPath) {
        generate(entity, "dao-interface.template", daoPath + "/I" + entity + "Dao.java");
    }

    void generateDaoClass(String entity, String daoPath) {
        generate(entity, "dao-impl.template", daoPath + "/" + entity + "Dao.java");
    }

    void generateEjbInterface(String entity, String ejbPath) {
        generate(entity, "ejb-interface.template", ejbPath + "/I" + entity + "Service.java");
    }

    void generateEjbClass(String entity, String ejbPath) {
        generate(entity, "ejb-impl.template", ejbPath + "/" + entity + "Service.java");
    }

    private void generate(String entity, String templateFileName, String daoPath) {
        BufferedReader br = null;
        BufferedWriter writer = null;
        try {
            File destPath = new File(daoPath);
            File tempplateFile = new File(templateFileName);
            String line = null, content = "";
            br = new BufferedReader(new FileReader(tempplateFile));
            while ((line = br.readLine()) != null) {
                line = line.replace("${entity}", entity) + "\n";
                content = content + line;
            }
            writer = new BufferedWriter(new FileWriter(destPath));
            writer.write(content);
            writer.flush();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(FileCreater.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public static void main(String[] args) {
        FileCreater creater = new FileCreater();
        List<String> list = new ArrayList<>();
        list.add("CaseType");
        creater.generateXmlProperty("za.co.fnb.cbs.config.persistence.model.", list, "D:/");
//        List<String> list = new ArrayList<>();
//        list.add("CaseType");
//        List<ClassProperties> generatedList = generatedList("za.co.fnb.cbs.config.persistence.model.", list);
//        for (ClassProperties classProperties : generatedList) {
//            StringBuilder content = new StringBuilder("<labelpackage name=\"")
//                    .append(classProperties.getName()).append("\">\n");
//            Map<String, String> propertyMap = classProperties.getPropertyMap();
//            for (Map.Entry<String, String> entry : propertyMap.entrySet()) {
//                String property = entry.getKey();
//                String simplified = entry.getValue();
//                content.append("    <label id=\"")
//                        .append(property)
//                        .append("\">")
//                        .append(simplified)
//                        .append("</label>\n");
//                content.append("    <label id=\"")
//                        .append(property)
//                        .append("required\">")
//                        .append(simplified)
//                        .append(" field is required</label>\n");
//            }
//            content.append("</labelpackage>");
//            System.out.println(content);
//        }
//        System.out.println("generatedList = " + generatedList);
        //        System.out.println(StringUtils.capitalize("employeeAddress"));
        //        String x = "EmployeeAddress";
        //        char[] toCharArray = x.toCharArray();
        //        String content = "";
        //        for (char c : toCharArray) {
        //            if (c != toCharArray[0] && Character.isUpperCase(c)) {
        //                content += " " + c;
        //            } else {
        //                content += c;
        //            }
        //        }
        //        System.out.println("content: " + content);

    }
}
